var _TIMEOUT_ = 60*2*1000;

function _DOM_clearChildren(parent) {
   while (parent.childNodes.length>0) {
      parent.removeChild(parent.childNodes.item(0));
   }
}

function AtomicOverlay() {
   this.discardSelect = false;
   this.XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
   this.context = null;
   this.postButton = null;
   this.contextButton = null;
   this.contextChooserBox = null;
   this.listbox = null;
   this.listboxData = {};
   this.posterBox = null;
   this.posterTitleBox = null;
   this.posterBoxContent = null;
   this.posterDeck = null;
   this.showSourceButton = null;
   this.xsltCache = new XSLTCache();
   this.editor = {
      control: null,
      doc : null,
      sourceMode: false,
      init: function(contextDoc) {
         this.control = contextDoc.getElementById('atomic-poster-editor-iframe');
         this.doc = this.control.contentWindow.document;
         this.div = this.doc.getElementById('content');
         this.textarea = this.doc.getElementById('source');
      },
      getContent: function() {
         return this.control.contentWindow.tinyMCE.getContent();
      },
      switchToSource: function() {
         var xml = this.getContent();
         this.detach();
         this.textarea.value = xml;
         this.div.style.display = "none";
         this.textarea.style.display = "block";
         this.sourceMode = true;
         return true;
      },
      switchToFormatted: function() {
         if (this.textarea.value.length==0) {
            this.div.style.display = "block";
            this.textarea.style.display = "none";
            this.attach();
            this.sourceMode = false;
            return true;
         }
         var serialized = this.textarea.value;
         serialized = "<div xmlns='http://www.w3.org/1999/xhtml'>"+serialized+"</div>";
         var xml = this._parseXHTMLSource(serialized);
         if (xml.wellFormed) {
            _DOM_clearChildren(this.div);
            var current = xml.div.firstChild;
            while (current) {
               this.div.appendChild(this.div.ownerDocument.importNode(current,true));
               current = current.nextSibling;
            }
            this.div.style.display = "block";
            this.textarea.style.display = "none";
            this.attach();
            this.sourceMode = false;
            return true;
         } else {
            throw xml.error;
         }
      },
      getXML: function() {
         var serialized = "";
         if (this.sourceMode) {
            var serialized = this.textarea.value;
         } else {
            var serialized = this.getContent();
         }
         serialized = "<div xmlns='http://www.w3.org/1999/xhtml'>"+serialized+"</div>";
         var xml = this._parseXHTMLSource(serialized);
         if (xml.wellFormed) {
            if (xml.div.firstChild && xml.div.firstChild.localName=="div" && xml.div.childNodes.length==1) {
               return xml.div.firstChild;
            } else {
               return xml.div;
            }
         } else {
            throw xml.error;
         }
      },
      _parseXHTMLSource: function(value) {
         var xmlParser = new DOMParser();
         var xmlDocument = xmlParser.parseFromString(value, 'text/xml');
         var roottag = xmlDocument.documentElement; 
         var ok = true;
         var error = null;
         if ((roottag.tagName == "parsererror") &&
             (roottag.namespaceURI == "http://www.mozilla.org/newlayout/xml/parsererror.xml")) {
            error = roottag.firstChild.textContent;
            ok = false;
         }
         return {
            wellFormed: ok,
            div: roottag,
            error: error
         }
      },
      attach: function() {
         this.control.contentWindow.tinyMCE.execCommand("mceAddControl",false,"content");     
      },
      detach: function() {
         this.control.contentWindow.tinyMCE.execCommand("mceRemoveControl",false,"content");         
      }
   };
   var theClass = Components.classes["@milowski.com/atomic;1"];
   var theComponent = theClass.getService(Components.interfaces.nsISupports);
   this.atomicService = theComponent.wrappedJSObject;
   LOG.level = this.atomicService.config.logLevel;
}
AtomicOverlay.prototype.doDelete = function() {
   if (!this.categorizeBox.hidden) {
      this.categories.deleteSelected();
   }
   if (!this.linksBox.hidden) {
      this.links.deleteSelected();
   }
}

AtomicOverlay.prototype.createEntry = function() {
   var tags = (this.tags.value+"").split(",");
   var div = null;
   try {
      var div = this.editor.getXML();
   } catch (e) {
      alert("Cannot get XML for entry: "+e);
      return;
   }
   var title = this.posterTitleBox.value;
   var entry = this.context.feed.addEntry(title);
   for (var i=0; i<tags.length; i++) {
      var tag = tags[i].replace(/^\s+|\s+$/, '');
      if (tag!="") {
         entry.addCategory(null,tag,null);
      }
   }
   var set = this.links.getLinks();
   for (var i=0; i<set.length; i++) {
      entry.addLink(set[i].rel,set[i].href,set[i].type,set[i].title);
   }
   var set = this.categories.getCategories();
   for (var i=0; i<set.length; i++) {
      entry.addCategory(set[i].scheme,set[i].term,set[i].value);
   }
   /*
   for (var i=0; i<this.links.childNodes.length; i++) {
      var item = this.links.childNodes[i];
      var rel = (item.childNodes[1].value+"").replace(/^\s+|\s+$/, '');
      var href = (item.childNodes[3].value+"").replace(/^\s+|\s+$/, '');
      var type = (item.childNodes[5].value+"").replace(/^\s+|\s+$/, '');
      if (href!="") {
         if (type=="") {
            type = null;
         }
         if (rel=="") {
            rel = "related";
         }
         entry.addLink(rel,href,type);
      }
   }
   for (var i=0; i<this.categories.childNodes.length; i++) {
      var item = this.categories.childNodes[i];
      var scheme = (item.childNodes[1].value+"").replace(/^\s+|\s+$/, '');
      var term = (item.childNodes[3].value+"").replace(/^\s+|\s+$/, '');
      var value = (item.childNodes[5].value+"").replace(/^\s+|\s+$/, '');
      if (term!="") {
         if (scheme=="") {
            scheme = null;
         }
         if (value=="") {
            value = null;
         }
         entry.addCategory(scheme,term,value);
      }
   }
   */
   var content = entry.getContent(true);
   content.type = "xhtml";
   content.setNodeContent(div);
   this.posterDeck.selectedIndex = 1;
   try {
      var currentApp = this;
      LOG.service.logStringMessage(entry.feed.collection.workspace.service.authorization);
      entry.save({
         timeout: _TIMEOUT_,
         onSuccess: function() {
            currentApp.posterDeck.selectedIndex = 0;
            currentApp.doPost();
         },
         onFailure: function(status,doc,msg) {
            alert("("+status+") "+doc.documentElement.textContent.substring(0,100))+"\n"+msg;
            currentApp.posterDeck.selectedIndex = 0;
         }
      });
   } catch (e) {
      alert(e);
      this.posterDeck.selectedIndex = 0;
   }
      
}

AtomicOverlay.prototype.doShowCollection = function(overlayElement) {
   // TODO: need to load plugins
   if (!this.xsltCache.transformers["feed-tree"]) {
      this.xsltCache.loadTransformFromURI('feed-tree','chrome://atomic/content/feed2tree-rdf.xsl',false,null);
   }      
   if (!this.atomicService.pluginsLoaded) {
      this.atomicService.loadPlugins();
   }
   var collection = this.context;
   window.openDialog("chrome://atomic/content/collection.xul",collection.url,"chrome,resizable",{
      title: collection.title,
      timeout: _TIMEOUT_,
      collection: collection,
      xsltCache: this.xsltCache,
      logLevel: LOG.level,
      plugins: this.atomicService.plugins
   }
   );
}


AtomicOverlay.prototype.doPost = function(overlayElement) {
   if (!this.context) {
      alert("You must set the context to a collection first.");
      return;
   }
   if (!this.posterBox) {
      this.posterBox = overlayElement.ownerDocument.getElementById('atomic-poster-box');
      if (!this.posterBox) {
         throw "Cannot find window overlay.";
      }
      this.statusBarHeight = overlayElement.ownerDocument.getElementById('status-bar').boxObject.height;
      this.posterBox.style.bottom = this.statusBarHeight+"px";
      this.posterTitleBox = overlayElement.ownerDocument.getElementById('atomic-poster-title');
      this.posterDeck = overlayElement.ownerDocument.getElementById('atomic-poster-deck');
      this.editor.init(this.posterBox.ownerDocument);
      this.showSourceButton = overlayElement.ownerDocument.getElementById('atomic-show-source');
      this.tagBox = overlayElement.ownerDocument.getElementById('atomic-poster-tag');
      this.tags = overlayElement.ownerDocument.getElementById('atomic-tags');
      this.categorizeBox = overlayElement.ownerDocument.getElementById('atomic-poster-categorize');
      this.linksBox = overlayElement.ownerDocument.getElementById('atomic-poster-links');
      this.links = new Links(overlayElement.ownerDocument.getElementById('atomic-links'));
      this.href = overlayElement.ownerDocument.getElementById('atomic-input-href');
      this.categories = new Categories(overlayElement.ownerDocument.getElementById('atomic-categories'));
      this.scheme = overlayElement.ownerDocument.getElementById('atomic-input-scheme');
      this.term = overlayElement.ownerDocument.getElementById('atomic-input-term');
   }
   if (!this.posterBox.hidden) {
      this.posterBox.hidden = true;
      this.tagBox.hidden = true;
      this.categorizeBox.hidden = true;
      this.linksBox.hidden = true;
      this.editor.detach();
      return;
   }
   
   this.posterDeck.selectedIndex = 0;
   this.posterBox.hidden = false;
   this.editor.attach();
}
AtomicOverlay.prototype._showButtonMenu = function(box,button,shift) {
   if (box.hidden) {
      this.tagBox.hidden = true;
      this.categorizeBox.hidden = true;
      this.linksBox.hidden = true;
      box.hidden = false;
      box.style.bottom = (this.statusBarHeight+button.boxObject.height+10)+"px";
      box.style.left = shift ? (button.boxObject.x+shift)+"px" : button.boxObject.x+"px";
   } else {
      box.hidden = true;
   }
}
AtomicOverlay.prototype.toggleTag = function(button) {
   this._showButtonMenu(this.tagBox,button);
}

AtomicOverlay.prototype.toggleCategorize = function(button) {
   this._showButtonMenu(this.categorizeBox,button,-200);
}

AtomicOverlay.prototype.toggleLinks = function(button) {
   this._showButtonMenu(this.linksBox,button,-100);
}

AtomicOverlay.prototype.toggleSource = function() {
   if (this.showSourceButton.label=="Source") {
      if (this.editor.switchToSource()) {
         this.showSourceButton.label = "Formatted";
      }
   } else {
      try {
         if (this.editor.switchToFormatted()) {
            this.showSourceButton.label = "Source";
         }
      } catch (e) {
         alert("The xhtml is not well-formed: "+e);
      }
   }
}

AtomicOverlay.prototype.selectCollection = function() {
   if (this.discardSelect) {
      return;
   }
   var url = this.listbox.selectedItem.getAttribute("id");
   var obj = this.listboxData[url];
   if (obj && obj.type==2) {
      this.context = obj;
      this.contextButton.label = this.context.title;
      this.updateButtons();
      this.contextChooserBox.hidden = true;
   }
}

AtomicOverlay.prototype.chooseContext = function(overlayElement) {
   if (!this.postButton) {
      var list = overlayElement.parentNode.childNodes;
      for (var i=0; i<list.length; i++) {
         var n = list.item(i);
         if (n.getAttribute("id")=="atomic-post") {
            this.postButton = n;
         } else if (n.getAttribute("id")=="atomic-collection") {
            this.contextButton = n;
         }
      }
      this.contextChooserBox = overlayElement.ownerDocument.getElementById('atomic-chooser-box');
      if (!this.contextChooserBox) {
         throw "Cannot find window overlay.";
      }
      this.listbox = overlayElement.ownerDocument.getElementById('atomic-chooser-listbox');
      this.contextChooserBox.style.bottom = overlayElement.ownerDocument.getElementById('status-bar').boxObject.height+"px";
   }
   if (!this.contextChooserBox.hidden) {
      this.contextChooserBox.hidden = true;
      return;
   }
   var child = this.listbox.firstChild;
   while (child) {
      var r= child;
      child = child.nextSibling;
      this.listbox.removeChild(r);
   }
   if (!this.atomicService.config.document) {
      LOG.debug("Loading configuration...");
      var current = this;
      this.atomicService.config.load({
         onSuccess: function() {
            current.atomicService.loadServices();
            current.finishChooseContext();
         },
         onFailure: function() {
            alert("Cannot load atomic configuration.");
         }
      });
      return;
   }
   this.finishChooseContext();
}

AtomicOverlay.prototype.finishChooseContext = function() {
   var count = 0;
   for (var url in this.atomicService.services) {
      count++;
      var service = this.atomicService.services[url];
      
      var item = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"richlistitem");
      item.setAttribute("id",service.url);
      
      var desc = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"description");
      desc.appendChild(this.listbox.ownerDocument.createTextNode(service.title));
      item.appendChild(desc);
      //desc.style.paddingLeft = 
      
      
      if (!service.loaded) {
         var offline = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"label");
         offline.setAttribute("value","(OFFLINE)");
         desc.appendChild(offline);
      }
      this.listbox.appendChild(item);
      this.listboxData[service.url] = service;
      if (!service.loaded) {
         var currentOverlay = this;
         var doLoad = function(target,serviceItem) {
            target.introspect({
               timeout: _TIMEOUT_,
               onSuccess: function() {
                  LOG.debug(target.url+" is loaded!");
                  currentOverlay.updateServiceList(target,serviceItem);
               },
               onFailure: function(status,doc) {
                  if (status!=0) {
                     LOG.info("Failed to contact service "+target.url+" ("+status+") due to:\n"+(doc ? doc.documentElement.textContent.substring(0,200) : ""));
                  }
               }
            });
         }
         doLoad(service,item);         
      } else {
         if (service.blogspot) {
            var doLogin = function(target,app) {
               app.atomicService.blogspotLogin(target.username,target.password,{
                  timeout: _TIMEOUT_,
                  onSuccess: function(auth) {
                     target.authorization = "GoogleLogin auth="+auth;
                  },
                  onFailure: function(status,doc,text) {
                     alert("("+status+") Failed to login as "+service.username+" for blog:\n"+service.url+"\n"+text);
                  }
               });
            };
            doLogin(service,this);
         }
         this.updateServiceList(service,item);
      }
   }
   this.contextChooserBox.hidden = false;
   this.updateChooserWidth();
   if (count>0) {
      var O = this;
      setTimeout(function() {
         O.discardSelect = true;
         if (O.context) {
            var item = O.listbox.firstChild;
            while (item && item.getAttribute("id")!=O.context.url) {
               item = item.nextSibling;
            }
            if (item) {
               O.listbox.selectedItem = item;
            }
         } else {
            O.listbox.selectedIndex = 0;
         }
         O.discardSelect = false;
      },
      150);
   }
   this.updateButtons();
}

AtomicOverlay.prototype.updateChooserWidth = function() {
   var width = this.listbox.boxObject.width+20;
   if (this.listbox.parentNode.boxObject.width<width) {
      this.listbox.parentNode.style.width = width+"px";
   }
}

AtomicOverlay.prototype.updateServiceList = function(service,listitem) {
   var offlineLabels = listitem.getElementsByTagName("label");
   if (offlineLabels.length>0) {
      offlineLabels.item(0).hidden = service.loaded;
   }
   var lastItem = listitem;
   for (var url in service.workspaces) {
      var workspace = service.workspaces[url];
      this.listboxData[workspace.id] = workspace;
      
      var item = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"richlistitem");
      item.setAttribute("id",workspace.id);
      
      var desc = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"description");
      desc.appendChild(this.listbox.ownerDocument.createTextNode(service.title+" - "+workspace.title));
      item.appendChild(desc);
      //desc.style.paddingLeft = "0.5em";
      
      if (lastItem.nextSibling) {
         lastItem.parentNode.insertBefore(item,lastItem.nextSibling);
      } else {
         lastItem.parentNode.appendChild(item);
      }
      lastItem = item;

      var context = [];
      var current = {
         list: workspace.children,
         index: 0
      };
      while (current && current.list && current.index<current.list.length) {
         var child = current.list[current.index];
         this.listboxData[child.url] = child;
         var item = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"richlistitem");
         item.setAttribute("id",child.url);
 
         var desc = this.listbox.ownerDocument.createElementNS(this.XUL_NS,"description");
         desc.appendChild(this.listbox.ownerDocument.createTextNode(child.title));
         item.appendChild(desc);
         desc.style.paddingLeft = (0.5*child.level + 0.5)+"em";
         
         if (lastItem.nextSibling) {
            lastItem.parentNode.insertBefore(item,lastItem.nextSibling);
         } else {
            lastItem.parentNode.appendChild(item);
         }
         lastItem = item;
         
         current.index++;
         
         if (child.children.length>0) {
            context.push(current);
            current = {
               list: child.children,
               index: 0
            };
         }
         if (current.index>=current.list.length) {
            if (context.length>0) {
               current = context.pop();
            }
         }
      }
   }
   if (service.loaded) {
      listitem.parentNode.removeChild(listitem);
   }
   if (!this.contextChooserBox.hidden) {
      this.updateChooserWidth();
   }
}

AtomicOverlay.prototype.updateButtons = function() {
   if (this.context) {
      this.postButton.disabled = false;
      this.contextButton.disabled = false;
   } else {
      this.postButton.disabled = true;
      this.contextButton.disabled = true;
   }
   
}

AtomicOverlay.prototype.addLink = function()
{
   var href = (this.href.value+"").replace(/^\s+|\s+$/, '');
   if (href=="") {
      return;
   }
   /*
   var item = this.links.ownerDocument.createElementNS(XUL_NS,"richlistitem");
   var label = this.links.ownerDocument.createElementNS(XUL_NS,"label");
   label.setAttribute("value","rel=");
   item.appendChild(label);
   var relE = this.links.ownerDocument.createElementNS(XUL_NS,"textbox");
   relE.setAttribute("class","plain");
   relE.setAttribute("value","related");
   relE.setAttribute("size",""+(href.length+1));
   relE.setAttribute("oninput","this.size=this.value.length+1");
   relE.setAttribute("flex","0");
   item.appendChild(relE);
   label = this.links.ownerDocument.createElementNS(XUL_NS,"label");
   label.setAttribute("value","href=");
   item.appendChild(label);
   var hrefE = this.links.ownerDocument.createElementNS(XUL_NS,"textbox");
   hrefE.setAttribute("class","plain");
   hrefE.setAttribute("value",href);
   hrefE.setAttribute("size",""+(href.length+1));
   hrefE.setAttribute("oninput","this.size=this.value.length+1");
   hrefE.setAttribute("flex","0");
   item.appendChild(hrefE);
   label = this.links.ownerDocument.createElementNS(XUL_NS,"label");
   label.setAttribute("value","type=");
   item.appendChild(label);
   var typeE = this.links.ownerDocument.createElementNS(XUL_NS,"textbox");
   typeE.setAttribute("class","plain");
   typeE.setAttribute("value","");
   typeE.setAttribute("size",""+(href.length+1));
   typeE.setAttribute("oninput","this.size=this.value.length+1");
   typeE.setAttribute("flex","0");
   item.appendChild(typeE);
   this.links.appendChild(item);
   */
   this.links.addLink('related',href,null,null);
   
}

AtomicOverlay.prototype.addCategory = function() {
   var scheme = (this.scheme.value+"").replace(/^\s+|\s+$/, '');
   var term = (this.term.value+"").replace(/^\s+|\s+$/, '');
   if (term=="") {
      return;
   }
   /*
   var item = this.categories.ownerDocument.createElementNS(XUL_NS,"richlistitem");
   item.setAttribute("class","category-item")
   var lbracket = this.categories.ownerDocument.createElementNS(XUL_NS,"label");
   lbracket.setAttribute("value","{");
   item.appendChild(lbracket);
   var schemeE = this.categories.ownerDocument.createElementNS(XUL_NS,"textbox");
   schemeE.setAttribute("class","plain");
   if (scheme) {
      schemeE.setAttribute("value",scheme);
      schemeE.setAttribute("size",""+(scheme.length+1));
   } else {
      schemeE.setAttribute("size","1");
   }
   schemeE.setAttribute("oninput","this.size=this.value.length+1");
   schemeE.setAttribute("flex","0");
   item.appendChild(schemeE);
   var rbracket = this.categories.ownerDocument.createElementNS(XUL_NS,"label");
   rbracket.setAttribute("value","}");
   item.appendChild(rbracket);
   var termE = this.categories.ownerDocument.createElementNS(XUL_NS,"textbox");
   termE.setAttribute("value",term);
   termE.setAttribute("class","plain");
   termE.setAttribute("size",""+(term.length+1));
   termE.setAttribute("oninput","this.size=this.value.length+1");
   termE.setAttribute("flex","0");
   item.appendChild(termE);
   var vequals = this.categories.ownerDocument.createElementNS(XUL_NS,"label");
   vequals.setAttribute("value"," = ");
   item.appendChild(vequals);
   var valueE = this.categories.ownerDocument.createElementNS(XUL_NS,"textbox");
   valueE.setAttribute("value","");
   valueE.setAttribute("class","plain");
   valueE.setAttribute("size","1");
   valueE.setAttribute("oninput","this.size=this.value.length+1");
   valueE.setAttribute("flex","0");
   item.appendChild(valueE);
   this.categories.appendChild(item);
   */
   this.categories.addCategory(scheme,term,null);
}
